(function (win, none){
	if(win.JS){return;}
	var JS,
		_Fn = Function,
		_slice = [].slice,
		_max = Math.max,
		_concat = [].concat,
		_guid = +new Date(),
		_toString = {}.toString,
		_random = Math.random,
		_has = {}.hasOwnProperty;
	function has(o, k){
		return _has.call(o, k);
	}
	function noop(a) {
		return a;
	}
	function intt(n){
		return parseInt(n, 10);
	}
	function _A() {
		return _slice.call.apply(_slice, arguments);
	}
	function _type(t) {
		return function (s){
			return _toString.call(s) === '[object ' + t + ']';
		};
	}
	var isObject = _type('Object'),
		isString = _type('String'),
		isFn = _type('Function'),
		isFunction = function (s){
			return isFn(s) && s.apply;
		},
		isNumber = _type('Number'),
		isBoolean = _type('Boolean'),
		isDate = _type('Date'),
		isRegExp = _type('RegExp'),
		isArray = _type('Array');
	function isEmpty(v) {
		return v === null || v === none;
	}
	function isNode(el, t) {
		return el && typeof el === 'object' && (t = el.nodeType) && (t === 1 || t === 9);
	}
	function isPlainObject(a) {
		return !!a && isObject(a) && isFunction(a.isPrototypeOf);
	}
	function arrayLike(o) {
		return typeof o === 'object' && isFinite(o.length) && o.nodeType === none && o.window !== o;
	}
	function forEach(o, f, z){
		var i = 0,
			j = o.length;
		for (; i < j; i++) {
			if (false === f.call(z || o[i], o[i], i, j, o)) {
				break;
			}
		}
		return z || o;
	}
	function forIn(o, f, z){
		var k, i = 0;
		for (k in (o || {})) {
			if (has(o, k) && false === f.call(z || o[k], o[k], k, i++, o)) {
				break;
			}
		}
		return z || o;
	}
	function each(o, f, z) {
		return (o && arrayLike(o)) ?
			forEach(o, f, z) : forIn(o, f, z);
	}
	function bind(o, f){
		var args = _A(arguments, 2);
		return function() {
			return f.apply(o, args.concat(_A(arguments)));
		};
	}
	function map(a, f, o){
		return each(a, function (v, k, j, a){
			this.push(f.call(o||v, v, k, j, a));
		}, []);
	}
	function filter(a, f, o){
		return forEach(a, function (v, k, j, a){
			if (f.call(o || v, v, k, j, a)) {
				this.push(v);
			}
		}, []);
	}
	function indexOf(a, v, s){
		var j = a.length,
		k = intt(s) || 0,
		i = k >= 0 ? k: _max(0, j + k);
		for (; i < j; i++) {
			if ((i in a) && a[i] === v) {
				return i;
			}
		}
		return -1;
	}
	function some(a, fn){
		for (var i = 0, j = a.length; i < j; i++) {
			if (fn.call(a[i], a[i], i, j, a)) {
				return true;
			}
		}
		return false;
	}
	function every(a, fn){
		for (var i = 0, j = a.length; i < j; i++) {
			if (!fn.call(a[i], a[i], i, j, a)) {
				return false;
			}
		}
		return true;
	}
	function reduce(a, fn, b, o){
		each(a, function (v, k, j, a){
			if (b === none) {
				b = v;
			}else{
				b = fn.call(o || v, b, v, k, j, a);
			}
		});
		return b;
	}
	function keys(o) {
		return forIn(o || {}, function (v, k){
			this.push(k);
		}, []);
	}
	function values(o){
		return forIn(o || {}, function (v, k){
			this.push(v);
		}, []);
	}
	function size(o) {
		return isEmpty(o) ? 0 : (o.length === +o.length ? o.length : keys(o).length);
	}
	function inArray(a, b, c){
		return (c ? filter : every)(isArray(a) ? a : [a], function (v){
			return indexOf(b, v) > -1;
		});
	}
	function arrayify(a){
		return forEach(a, function (v, i){
			this[i] = v;
		}, []);
	}
	function flatten(){
		return _concat.apply([], forEach(arguments, function (s){
			this.push(arrayLike(s) ? arrayify(s) : s);
		}, []));
	}
	function assy() {
		var args = _A(arguments),
			v = args.pop();
		return forEach(args, function (k){
			this[k] = v;
		}, {});
	}
	function Enum(keys, o){
		var n = 0;
		return forEach(keys, function (v, i){
			if (isArray(v)) {
				n = isNumber(v[1]) ? intt(v[1]) : n;
				v = v[0];
			}
			this[v] = n++;
		}, o || win);
	}
	function func(f, d) {
		return isFunction(f) ? f: (isFunction(d) ? d: noop);
	}
	function getGuid(g) {
		return (g || 'guid') + '_' + intt(_random()*9e5).toString(16) + '_' + (++_guid).toString(16);
	}
	function unique(arr, lax) {
		var ref = {},
			objs = [],
			items = [],
			key = getGuid('unique'),
			simple = '|string|boolean|number';
		forEach(arr, function (item, type, k){
			if (!isEmpty(item)){
				type = typeof item;
				if (simple.indexOf(type) > 0) {
					k = (lax ? '' : type) + item;
					if (!(k in ref)) {
						ref[k] = 1;
						items.push(item);
					}
				} else {
					if (!item[key]){
						item[key] = 1;
						objs.push(item);
						items.push(item);
					}
				}
			}
		});
		for (var i = objs.length; i--;) {
			delete objs[i][key];
		}
		return items;
	}
	function classify(f, p) {
		f = func(f, _Fn());
		f.fn = f.prototype = p || {};
		return f;
	}
	function fire(fs, o, d){
		d = isArray(d) ? d : [];
		forEach(fs, function (f){
			if (isFunction(f) && false === f.apply(o, d)) {
				return false;
			}
		});
	}
	function extend(o){
		var args, len, skip;
		function save(v, k){
			if (!skip || !(k in o)) {
				o[k] = v;
			}
		}
		if (o) {
			args = arguments;
			len = args.length;
			skip = false === args[len-1];
			for (var i = 1; i < len; i++) {
				forIn(args[i], save);
			}
		}
		return o;
	}
	function ExtThis(a, b){
		return extend(this, isString(a) ? assy(a, b) : (isFunction(a) ? a.call(this, this, JS) : a));
	}
	function Cache(def, vf){
		this.__cache__ = {};
		if (def !== none) {
			this.def = def;
			this.vf = vf;
		}
	}
	extend(Cache.prototype, {
		has: function (k){
			return has(this.__cache__, k);
		},
		set: function (k, v){
			this.__cache__[k] = v;
		},
		get: function (k, def, vf){
			var l = arguments.length,
				o = this.__cache__;
			if (l) {
				if (!this.has(k)) {
					if (def === none && this.def !== none){
						def = this.def;
						vf = this.vf;
					}
					if (def !== none) {
						this.set(k, (!vf && isFunction(def)) ? def.call(this, k) : def);
					}
				}
			}
			return l ? o[k] : o;
		}
	});
	function groupBy(a, v) {
	  var sg = arguments.length <2,
		  vf = isFunction(v),
		  g = function (o){
				return sg ? o : (vf ? v.call(o, o) : o[v]);
		  };
		return forEach(a, function (o){
			this.get(g(o)).push(o);
		}, new Cache(function (){
			return [];
		})).get();
	}
	function countBy(){
		return forIn(groupBy.apply(null, arguments), function (v, k){
			this[k] = v.length;
		}, {});
	}
	var Dir, TaskAPI,
		SPLIT_STR_RE = /[^, ]+/g,
		TRIM_RE = /^\s+|\s+$/g,
		SPLIT_NS_RE = /[\w@\-\$\*!~\:>#]+/g,
		CLASS_RE = /^[A-Z]\w*$/,
		IEV_RE = /msie\s*(\d+)/i,
		FOModuleATSTR_RE = /\{([^\}]*)\}/g,
		EQUATION_RE = /([^=;&?# ]+)\s*=\s*([^=;&?# ]+)/g,
		NS_SPLIT_RE = /^((?:\w+\.)*)(\w*)$/,
		RMB_RE = /(\d)(?=(\d{3})+($|\.))/g;

	function trim(s){
		return s.replace(TRIM_RE, '');
	}
	Dir = classify(false, {
		toString: _Fn("return '[object Namespace]';")
	});
	function toArray(v) {
		if (isEmpty(v)) {
			return [];
		}
		if (isArray(v)) {
			return v.slice();
		}
		if (isString(v)) {
			return v.match(SPLIT_STR_RE) || [];
		}
		if(arrayLike(v)) {
			return arrayify(v);
		}
		return [v];
	}
	function namespace(path) {
		var b = this,
			s = isString(path);
		if (s) {
			forEach(path.match(SPLIT_NS_RE) || [], function (p){
				if(has(b, p)) {
					if (!(b[p] instanceof Dir)) {
						throw Error('Invalid namespace object "' + p + '"');
					}
				} else {
					b[p] = new Dir();
				}
				b = b[p];
			});
		}else{
			b = new Dir();
		}
		return ExtThis.apply(b, _A(arguments, s ? 1 : 0));
	}
	function parseNS(str, o){
		var real = {},
			g = JS.trim(str).match(NS_SPLIT_RE);
		if (!g) {
			throw Error('Invalid split namespace "' + str + '"');
		}
		real.path = g[1] ? namespace(g[1].slice(0, -1)) : o || win;
		real.name = g[2];
		real.value = real.path[g[2]];
		return real;
	}
	JS = namespace("JS");
	TaskAPI = {
		STATES: Enum(['done', 'error', ['progress', 1] , 'stop'], {}),
		update: function(d, i, s) {
			var e = this.thens,
			_do = i > this.STATES.error ? [] : toArray(e[i]);
			this.data = d;
			this.state = s;
			if (s !== 'progress') {
				_do = _do.concat(e[2]);
				e.length = 0;
				this.update = function() {
					return this;
				};
				this.isEnd = true;
			}
			fire(_do, this.context, d);
			return this;
		},
		and: function (){
			return JS.when(flatten(this, arguments));
		},
		then: function(a, b, c) {
			return each([a, b, c], function(f, i) {
				if (isFunction(f)) {
					if (this.isEnd) {
						if (i === this.STATES[this.state] || i > 1) {
							f.apply(this.context, this.data);
						}
					} else {
						this.thens[i].push(f);
					}
				}
			}, this);
		}
	};
	forIn(TaskAPI.STATES, function(i, s) {
		TaskAPI[s] = function() {
			return this.update(_A(arguments), i, s);
		};
	});
	function createTask(o) {
		var task = function() {
			return task.then.apply(task, arguments);
		};
		task.context = o || task;
		task.thens = [[], [], []];
		return extend(task, TaskAPI);
	}
	var message, StdCore,
		doc = document,
		IEA = win.ActiveXObject,
		SPLIT_URL_RE = /^([^\?]+)(?:(\?[^#]+)?(#.*)?)?$/,
		Agent = navigator.userAgent,
		ie = IEA ? intt((Agent.match(IEV_RE)||[0, 48])[1]) : false;
	StdCore = {
		__initbefore__: noop,
		__NotListening__: noop,
		initialize: function() {
			this.callSuper.apply(this, flatten('initialize', arguments));
		},
		callSuper: function(n) {
			var k = '!turn-point',
				args = _A(arguments, 1),
				r, a;
			if (! (k in this)) {
				this[k] = this;
			}
			a = this[k]['super'];
			while (a && !has(a, n)) {
				a = a['super'];
			}
			if (a) {
				this[k] = a;
				r = a[n].apply(this, args);
			}
			delete this[k];
			return r;
		},
		toString: function() {
			return '[object ' + this.guid + ']';
		},
		on: function(n, f, z) {
			if (isString(n)) {
				if (n.indexOf(',') > -1) {
					return each(toArray(n), function (v){
						this.on(v, f, z);
					}, this);
				}
				var me = this,
				s = this.__EVENTS__.get(n),
				g = function() {
					return f.apply(me, arguments);
				};
				s.push([f, g]);
				if ('lastCall' in s && z) {
					g.apply(this, s.lastCall);
				}
			} else if (isFunction(n)) {
				this.__NotListening__ = n;
			}
			return this;
		},
		once: function(n, f, z) {
			var f1 = function(e) {
				this.un(n, f1);
				f.call(this, e);
			};
			return this.on(n, f1, z);
		},
		un: function(t, f) {
			var s = this.__EVENTS__.get(t);
			if (arguments.length == 1) {
				s.length = 0;
			} else {
				for (var i = s.length; i--;) {
					if (s[i][0] === f) {
						s.splice(i, 1);
					}
				}
			}
			return this;
		},
		trigger: function(n) {
			var A = arguments,
			args = _A(A, 1),
			es = this.__EVENTS__.get(n);
			es.lastCall = args;
			if (!es.length) {
				this.__NotListening__.apply(this, A);
			}else{
				fire(map(es, function (f){
					return f[1];
				}), this, args);
			}
		},
		change: function (e, f, z){
			if (isString(e)) {
				return this.on('change:' + e, f, z);
			}else if(isFunction(e)){
				return this.on('change', e, f);
			}else {
				return forIn(e, function (f, d){
					this.change(d, f, z);
				}, this);
			}
		},
		oncall: function (a, b, c){
			this[a] = JS.aop(this[a], b);
			return this;
		},
		uncall: function (a){
			var fn = this[a];
			this[a] =fn ? (fn._AOP_ORIGIN || fn) : fn;
			return this;
		},
		destroy: function() {
			this['class']._INSTANCE = null;
			this.trigger('destroy');
			each(this, function(v, k, o) {
				delete o[k];
			});
			this.__isdestroyed__ = Date.now();
		},
		extend: ExtThis,
		bind: function (s){
			var m = this;
			return isFunction(s) ? bind(this, s) : this.__BINDCACHE__.get(s, function (){
				m[s].apply(m, flatten(arguments, this));
			}, true);
		},
		set: function (k, v){
			if (isString(k)) {
				var d = this.defaultVal(k);
				this.__PRIVATEDATA__[k] = v = func(this.set[k]).call(this, v, d);
				this.trigger('change:' + k, v, d);
				return this;
			}else{
				return each(k, function (w, s){
					this.set(s, w);
				}, this);
			}
		},
		get: function (k){
			return k !== none ? func(this.get[k]).call(this, this.defaultVal(k)) : this.__PRIVATEDATA__;
		},
		defaultVal: function (k){
			return this.has(k) ? this.__PRIVATEDATA__[k] : (this.defaults ? this.defaults[k] : none);
		},
		has: function (k){
			return has(this.__PRIVATEDATA__, k);
		},
		stringify: function (tpl){
			return tpl ? JS.stringify(tpl, this) : '';
		},
		ui: function (o, v){
			return forIn(isString(o) ? assy(o, v) : o, function(v, k) {
				this[k] = win.jQuery(v);
			}, this.ui);
		}
	};
	function createInit(name, single) {
		function Class() {
			var ic = this['class'],
			a = _A(arguments);
			if (a[0] !== createInit) {
				return new Class(createInit, a);
			}
			if (single) {
				if (ic._INSTANCE) {
					return ic._INSTANCE;
				} else {
					ic._INSTANCE = this;
				}
			}
			this.guid = getGuid(name);
			this.__EVENTS__ = new Cache(function (){
				return [];
			});
			this.__BINDCACHE__ =  new Cache();
			this.__PRIVATEDATA__ = {};
			this.__initbefore__.apply(this, a[1]);
			this.initialize.apply(this, a[1]);
		}
		Class.toString = _Fn('return "[class ' + name + ']"');
		return Class;
	}
	function Class() {
		var single, _super, des, _class, ns, sns, run,
		name = '',
		base = StdCore,
		exts = [];
		forEach(arguments, function(a) {
			if (isString(a)) {
				name = a;
			} else if (isArray(a) || a === JS.ready) {
				run = a;
			} else if (isFunction(a)) {
				exts.push({initialize: a});
			} else if (a === true) {
				single = true;
			} else if (isPlainObject(a)) {
				exts.push(a);
				_super = _super || a.extends_;
			}
		});
		if (name) {
			sns = parseNS(name, this);
			name = sns.name;
			ns = sns.path;
		}
		if (name && !CLASS_RE.test(name)) {
			throw Error('Invalid class name "' + name + '"');
		}
		if (_super) {
			base = isFunction(_super) ? _super.fn : _super;
			if (!JS.isStdObject(base)) {
				throw Error("Invalid super class");
			}
		}
		des = new(classify(0, base))();
		_class = classify(createInit(name || '*', single), des);
		extend(_class.fn, {
			'super' : base,
			'class': _class
		});
		if (name) {
			if (has(ns, name)) {
				throw Error('class "' + name + '" is exists');
			}
			ns[name] = _class;
		}
		extend.apply(0, flatten(des, exts));
		if (run) {
			JS.when(run).then(_class);
		}
		return _class;
	}
	extend(JS, {
		modern: '__proto__' in {},
		Cache: Cache,
		fire: fire,
		ie: function (a, b){
			return [ie, ie === a, ie >= a && ie <= b][arguments.length];
		},
		match: function(s, r) {
			var b = [], t;
			r.lastIndex = 0;
			do {
				t = r.exec(s);
				if (t) {
					b.push(t);
				}
			} while ( t && r.global );
			return b;
		},
		unserialize: function(str, en, r) {
			var f = func(en);
			return forEach(JS.match(str, r || EQUATION_RE), function(v, i) {
				this[v[1]] = f(v[2]);
			}, {});
		},
		serialize: function(obj) {
			return forIn(obj, function(v, k) {
				var v2 = k + '=' + v;
				if (isArray(v)) {
					var k2 = k + '[]=';
					v2 = k2 + v.join('&' + k2);
				}
				this.push(v2);
			}, []).join('&');
		},
		addParam: function (url, data){
			return url.replace(SPLIT_URL_RE, function (a, m, p, h){
				a = JS.toParam(extend({}, JS.parse(p), data));
				return m + (a ? ('?' + a) : '') + (h || '');
			});
		},
		rndUrl: function (url){
			return JS.addParam(url, {_rnd: Date.now()});
		},
		stringify: function(tpl, d, em) {
			return map(isArray(d) ? d : [d], function (d){
				var std = JS.isStdObject(d);
				return d ? tpl.replace(FOModuleATSTR_RE, function(s, w) {
					var v = w ? (std ? d.get(w) : d[w]) : d;
					return isEmpty(v) ? (em === false ? s : ''): v;
				}) : '';
			}).join('');
		},
		formatDate: (function() {
			var w = '\u65e5\u4e00\u4e8c\u4e09\u56db\u4e94\u516d',
				R = map('yy,yyyy,m,mm,d,dd,H,h,G,g,i,s,u,w,a'.split(','), function (f){
					return RegExp('\\b' + f + '\\b', 'g');
				}),
				z = function (n, b){
					return ('00' + n).slice(-(b || 2));
				};
			return function(date, t) {
				var d = JS.toDate(date),
				o = [0, d.getFullYear(), d.getMonth() + 1, 3, d.getDate(), 5, 6, 7, d.getHours(), 9, d.getMinutes(), d.getSeconds(), z(d.getMilliseconds(), 3), w.charAt(d.getDay())],
				a = o[8] > 12;
				o[0] = (o[1]+'').slice(-2);
				o[3] = z(o[2]);
				o[5] = z(o[4]);
				o[9] = o[8] - (a ? 12 : 0);
				o[6] = z(o[8]);
				o[7] = z(o[9]);
				o[14] = (a ? '\u4e0b' : '\u4e0a') + '\u5348';
				return reduce(R, function (f, r, i){
					return f.replace(r, o[i]);
				}, t || 'yyyy-mm-dd H:i:s').replace(/`/g, '');
			};
		})(),
		toDiff: function(d, z) {
			return reduce([8.64e7, 3.6e6, 6e4, 1e3, 1], function(a, b) {
				var v = Math.floor(d / b);
				d %= b;
				return a.concat((z && v < 10 ? '0' : '') + v);
			}, []);
		},
		toDate: function(d) {
			return JS.isDate(d) ? d: (new Date(isString(d) ? d.replace(/-/g, '/') : d));
		},
		result: function(v, o) {
			return isFunction(v) ? v.call(o, o) : v;
		},
		toRmb: function(n, f, l) {
			var s = parseFloat(n).toFixed(l === none ? 2 : l).toString().split('.');
			s[0] = s[0].replace(RMB_RE, '$1,');
			return (f === false ? '': '\uffe5') + s.join('.');
		},
		isStdObject: function(o) {
			return StdCore === o || StdCore.isPrototypeOf(o);
		},
		parseJSON: function(s) {
			try {return _Fn('return (' + s + ')')();} catch(e) {}
		},
		refresh: (function(b, w) {
			return bind(w, (w['r' + b] || w['oR' + b] || w['webkitR' + b] || w['mozR' + b] || w['msR' + b] || function(f) {
				setTimeout(f, 10);
			}));
		})('equestAnimationFrame', win),
		random: function(a) {
			return forEach(a, function (v, i, j, k){
				k = Math.floor(_random() * j);
				a[i] = a[k];
				a[k] = v;
			}, a);
		},
		range: function (v, a, b, c){
			return v > b ? (c ? a : b) : (v < a ? (c ? b : a) : v);
		},
		now: function() {
			return new Date().getTime();
		},
		trim: trim,
		aop: function (fn, a, b){
			var AF, _ = isFunction;
			if (!_(fn)) {
				throw Error('aop target is not a function');
			}
			AF = function (){
				var args = _A(arguments), ret;
				if (_(a)) {
					ret = a.call(this, args);
				}
				if (ret && ret.stop === true) {
					return ret.returnValue;
				}
				ret = fn.apply(this, args);
				if (_(b)) {
					ret = b.call(this, args, ret);
				}
				return ret;
			};
			AF._AOP_ORIGIN = fn._AOP_ORIGIN || fn;
			return AF;
		},
		task: function(init, o) {
			var t = createTask(o);
			if (isFunction(init)) {
				init.call(o, t, o);
			}
			return t;
		},
		isTask: function(t) {
			return t && t.and === TaskAPI.and;
		},
		toTask: function(a, o) {
			if (!JS.isTask(a)) {
				if (isNumber(a)) {
					return JS.task(function (tk){
						setTimeout(function() {
							tk.done();
						}, a);
					}, o);
				} else if (isFunction(a)) {
					a = a.call(o);
				} else if (a && (isString(a) || a.url)) {
					a = JS.use(a);
				} else if (isArray(a)) {
					a = JS.when(a, o);
				}
			}
			return a;
		},
		when: function(ts, o) {
			return JS.task(function(tk) {
				var check, q = toArray(ts),
					all = indexOf(q, true) > -1 || q.async,
					len = q.length,
					i = 0;
				function next() {
					var cur = JS.toTask(q.shift(), o);
					if (all && q.length) {
						next();
					}
					return JS.isTask(cur, o) ? cur.then(0, 0, check) : check(_A);
				}
				check = function(z) {
					i++;
					if (z !== _A) {
						tk.progress(z, intt(i / len * 100), i, len);
					}
					if (!all) {
						return q.length ? next() : tk.done(i, len);
					} else if (i >= len) {
						tk.done(i, len);
					}
				};
				next();
			}, o);
		},
		some: some,
		every: every,
		forEach: forEach,
		map: map,
		indexOf: indexOf,
		reduce: reduce,
		filter: filter,
		forIn: forIn,
		each: each,
		inArray: inArray,
		has: has,
		func: func,
		assy: assy,
		noop: noop,
		intt: intt,
		args: _A,
		arrayify: arrayify,
		flatten: flatten,
		groupBy: groupBy,
		countBy: countBy,
		keys: keys,
		values: values,
		size: size,
		Enum: Enum,
		classify: classify,
		parseNS: parseNS,
		extend: extend,
		toArray: toArray,
		bind: bind,
		guid: getGuid,
		unique: unique,
		arrayLike: arrayLike,
		isString: isString,
		isObject: isObject,
		isArray: isArray,
		isNode: isNode,
		isNumber: isNumber,
		isDate: isDate,
		isRegExp: isRegExp,
		isBoolean: isBoolean,
		isFunction: isFunction,
		isPlainObject: isPlainObject,
		isEmpty: isEmpty
	});
	Class('JS.StdClass', function (){
		ExtThis(this, arguments);
	});
	message = JS.StdClass();
	message.send = message.trigger;
	var cwd, scripts, Engine, base, setting, AppStart,
		head = doc.getElementsByTagName('head')[0] || doc.documentElement,
		URICache = new Cache(),
		LoadCache = new Cache(),
		DIRNAME_RE = /[^?#]*\//,
		DOT_RE = /\/\.\//g,
		RESLASH_RE = /([^:\/])\/\/+/g,
		DOT2_RE = /\/[^\/]+\/\.\.\//g,
		ABS_RE = /:\//,
		REL_RE = /^\./,
		ROOT_RE = /^\//,
		ROOT_DIR_RE = /^.*?\/\/.*?\//,
		PATHS_RE = /^([^\/\:]+)(\/.+)$/,
		URI_END_RE = /\?|\.(?:css|js)$|\/$/,
		HASH_END_RE = /#$/,
		ISCSS_RE = /\.css(?:\?|$)/i,
		ISREADY_RE = /^(loaded|complete|undefined)$/,
		BASE_RE = /^.*?\/(?=then)/,
		lt536 = (Agent.replace(/.*AppleWebKit\/(\d+)\..*/, "$1")) * 1 < 536;
	function debug(s, t){
		try{
			return JS._log ? JS._log(s) : console[t || 'log'](s);
		}catch(e){}
	}
	function dirname(path) {
		return path.match(DIRNAME_RE)[0];
	}
	function element(tag, attr, ap){
		var el = tag == 'text' ? doc.createTextNode(attr) : forIn(attr || {}, function (v, k){
			this.setAttribute(k, v);
		}, doc.createElement(tag));
		return ap ?  ap.appendChild(el) : el;
	}
	cwd = dirname(location.href);
	scripts = doc.getElementsByTagName("script");
	Engine = doc.getElementById("thenjs_node") || scripts[scripts.length - 1];
	AppStart = Engine.getAttribute('data-main');
	base = ((Engine.hasAttribute ? Engine.src : Engine.getAttribute("src", 4)).match(BASE_RE) || [cwd])[0];
	setting = {
		timeout: 7,
		charset: 'utf-8',
		alias: {},
		vars: {},
		paths: {'~': cwd},
		map: [],
		autoload: []
	};
	function config(conf, b){
		if (isString(conf)) {
			conf = assy(conf, b);
		}
		forIn(conf, function (v, type){
			var ini = setting[type];
			if(isPlainObject(ini)){
				if (isPlainObject(v)) {
					return extend(ini, v);
				}
			}else if (isArray(ini)) {
				setting[type] = filter(ini.concat(v), noop);
			}else{
				setting[type] = v;
			}
		});
		return setting;
	}
	function getRoot(path){
		return (path.match(ROOT_DIR_RE) || ['/'])[0];
	}
	function trimPath(path) {
		path = path.replace(DOT_RE, "/")
			.replace(RESLASH_RE, "$1\/");
		while (path.match(DOT2_RE)) {
			path = path.replace(DOT2_RE, "/");
		}
		return path;
	}
	function getFullPath(id, ref, ext) {
		if (!ABS_RE.test(id)) {
			if (REL_RE.test(id)) {
				id = dirname(ref || cwd) + id;
			}else if (ROOT_RE.test(id)) {
				id = getRoot(cwd) + id.slice(1);
			}else{
				id = base + id;
			}
		}
		if (ext) {
			if (HASH_END_RE.test(id)) {
				id = id.slice(0, -1);
			}else if (!URI_END_RE.test(id)) {
				id += ext;
			}
		}
		return id;
	}
	function mapPath(path, maps){
		forEach(maps, function (item, ret){
			if (isFunction(item)) {
				ret = item(path);
				if (ret && ret !== path) {
					path = ret;
				}
			}else if(isArray(item)){
				path = path.replace(item[0], item[1]);
			}
		});
		return path;
	}
	function formatURI(id, ref, ext){
		if (!isString(id)) {
			return '';
		}
		id = trim(id);
		ref = ref || '';
		ext = ext || '.js';
		return id ? URICache.get(( ref + id + ext), function (){
			var uri = setting.alias[id] || id;
			uri = uri.replace(PATHS_RE, function (a, head, end){
				return  (setting.paths[head] || head) + end;
			});
			uri = trimPath(getFullPath(JS.stringify(uri, setting.vars, false), ref, ext));
			uri = mapPath(uri, setting.map);
			URICache.set(uri, uri);
			return uri;
		}) : '';
	}
	win.URICache = URICache;
	function removeLoader(node, css, then){
		if (!css) {
			head.removeChild(node);
		}
		node.onload = node.onerror = node.onreadystatechange = null;
		then();
	}
	function listenCss(node, then) {
		var end, sheet = node.sheet;
		if (lt536) {
			end = !!sheet;
		}else if (sheet) {
			try {
				end = !!sheet.cssRules;
			} catch (e) {
				end = e.name === "NS_ERROR_DOM_SECURITY_ERR";
			}
		}
		setTimeout(function() {
			return end ? then() : listenCss(node, then);
		}, 10);
	}
	function onResponse(node, then, css){
		if (css && (lt536 || !("onload" in node))) {
			return setTimeout(function() {
				listenCss(node, then);
			}, 1);
		}
		var timeout = setTimeout(function() {
			removeLoader(node, css, then);
		}, setting.timeout*1e3);
		node.onload = node.onerror = node.onreadystatechange = function() {
			if (ISREADY_RE.test(node.readyState)) {
				clearTimeout(timeout);
				removeLoader(node, css, then);
				node = none;
			}
		};
	}
	function request(url, charset) {
		return LoadCache.get(url, function (){
			var first = head.firstChild,
				css = ISCSS_RE.test(url),
				node = element(css ? "link" : "script");
			return JS.task(function (tk){
				onResponse(node, function (){
					tk.done(url);
				}, css);
				node.charset = charset || setting.charset;
				if (css) {
					node.rel = "stylesheet";
					node.href = url;
				}else {
					node.async = true;
					node.src = url;
				}
				node = first ? head.insertBefore(node, first) : head.appendChild(node);
			});
		});
	}
	function load(url, fn, o){
		return JS.when(map(flatten(setting.autoload, toArray(url)), function (u){
			if (isFunction(u)) {
				u = u();
			}
			if (isString(u) && trim(u)) {
				u = assy('url', u);
			}
			return u && u.url ? function (){
				return request(formatURI(u.url), u.charset);
			} : u === true;
		}), o).then(fn);
	}
	extend(JS, {
		Class: Class,
		config: config,
		getRoot: getRoot,
		dirname: dirname,
		trimPath: trimPath,
		formatURI: formatURI,
		getFullPath: getFullPath,
		element: element,
		style: function (t){
			if (doc.createStyleSheet) {
				doc.createStyleSheet().cssText += t;
			} else {
				element('text', t, element('style', {
					type: 'text/css'
				}, head));
			}
		},
		cwd: function (){
			return cwd;
		},
		base: function (){
			return base;
		},
		use: load,
		message: message,
		ready: function (fn){
			return JS.task(function (tk, o){
				load([], function (){
					function then(){
						func(fn).call(o, o);
						tk.done();
					}
					return win.jQuery(then);
				});
			}, this);
		},
		delay: function (fn,time){
			var stopId, statu;
			function stop(n){
				var end = statu !== 1;
				clearTimeout(stopId);
				statu = n;
				return end;
			}
			function trigger(){
				stop(3);
				fn.apply(this, arguments);					
			}
			return extend(function (){
				var o = this,
					args = _A(arguments);
				if (statu !== 3) {
					stop(1);
					stopId = setTimeout( function (){
						trigger.apply(o, args);
					}, time || 64);
				}
			}, {trigger: trigger, stop: stop});
		}
	});
	extend(win, {
		namespace: namespace,
		log: debug,
		imports: function (a){
			config('autoload', toArray(a));
		}
	});
	config('autoload', [!win.jQuery ? 'jquery' : '', win.JSON ? '' : 'json']);
	if (AppStart) {
		load(AppStart);
	}
	debug('ThenJS is ready');
})(this);